package com.semp.gu.codec.video;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.semp.gu.codec.AbstractCodec;
import com.semp.gu.config.IConfigurationManager;
import com.semp.gu.domain.local.LocalAlbumElement;

public class VideoCodec extends AbstractCodec {

	private VideoCodecConfiguration	configuration;
	private VideoCodecConfiguration	defaultConfiguration;
	private IConfigurationManager	configurationManager;
	private final static Logger		logger	= LoggerFactory.getLogger(VideoCodec.class);

	public VideoCodec() {
		super("video");
	}

	public void processElement(LocalAlbumElement element) throws IOException {
		processMovie(element);
		processImage(element);
	}

	/*
	 * Convert Movie
	 */
	private void processMovie(LocalAlbumElement element) throws IOException {
		/*
		 * Output file naming
		 */
		File inputFile = element.getFile();
		String fileNameWithoutSuffix = inputFile.getName().substring(0, inputFile.getName().lastIndexOf('.'));
		File convertedFile = new File(getWorkingFolder() + File.separator + fileNameWithoutSuffix + "." + configuration.getVideoOutputFormat());
		logger.info("Converting {} into {}", inputFile, convertedFile);

		/*
		 * FFmpeg command preparation
		 */
		String command = FfmpegUtil.generateVideoCommand(configuration, inputFile, convertedFile);

		/*
		 * Exec command
		 */
		execCommandLine(command);
		/*
		 * Add converted element
		 */
		element.getConvertedFileList().add(convertedFile);
	}

	/*
	 * Extract image
	 */
	private void processImage(LocalAlbumElement element) throws IOException {
		/*
		 * Output file naming
		 */
		File inputFile = element.getFile();
		String fileNameWithoutSuffix = inputFile.getName().substring(0, inputFile.getName().lastIndexOf('.'));
		File convertedFile = new File(getWorkingFolder() + File.separator + fileNameWithoutSuffix + "." + configuration.getImageOutputFileExt());
		logger.info("Converting {} into {}", inputFile, convertedFile);

		/*
		 * FFmpeg command preparation
		 */
		String command = FfmpegUtil.generateImageCommand(configuration, inputFile, convertedFile);

		/*
		 * Exec command
		 */
		execCommandLine(command);
		/*
		 * Add converted element
		 */
		element.getConvertedFileList().add(convertedFile);
	}

	/*
	 * Execute a command line
	 */
	private void execCommandLine(String command) throws IOException {
		logger.debug("Exec {} ", command);

		/*
		 * Exec command
		 */
		Process process = Runtime.getRuntime().exec(command);
		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(process.getErrorStream()));
			String line = null;
			while ((line = br.readLine()) != null) {
				logger.debug(line);
			}

			int retCode = process.waitFor();
			if (retCode != 0) {
				logger.error("Process finished in a unexpected way, return code = {}", retCode);
				throw new IOException("Process finished in a unexpected way, return code retCode");
			}
		} catch (InterruptedException e) {
			throw new IOException(e);
		}
	}

	// Getters & Setters

	private void loadConfiguration(IConfigurationManager configurationManager, VideoCodecConfiguration defaultConfiguration) throws IOException {
		if (configurationManager != null && defaultConfiguration != null) {
			configuration = (VideoCodecConfiguration) configurationManager.loadConfiguration(defaultConfiguration);
		}
	}

	public VideoCodecConfiguration getDefaultConfiguration() {
		return defaultConfiguration;
	}

	public void setDefaultConfiguration(VideoCodecConfiguration defaultConfiguration) throws IOException {
		this.defaultConfiguration = defaultConfiguration;
		loadConfiguration(configurationManager, defaultConfiguration);
	}

	public IConfigurationManager getConfigurationManager() {
		return configurationManager;
	}

	public void setConfigurationManager(IConfigurationManager configurationManager) throws IOException {
		this.configurationManager = configurationManager;
		loadConfiguration(configurationManager, defaultConfiguration);
	}

}
